package principal;

import java.util.ArrayList;

import opciones.Opciones;

import utils.Arbol;

public class Tablero {	
	private ArrayList<Character> _pila;
	private ArrayList<Character> _mesa;
	private int _CP;
	private int _BS;
	private int _SN;
	
	private Tablero() {
		_pila = null;
		_mesa = null;
	}
	
	public Tablero(String configuracion) {
		_pila = new ArrayList<Character>();
		_mesa = new ArrayList<Character>();
		String[] splittedStr = configuracion.replace(" ", "").split("\\*");
		for (int iChar = 0; iChar < splittedStr[0].length(); iChar++)
			_pila.add(splittedStr[0].charAt(iChar));
		for (int iChar = 0; iChar < splittedStr[1].length(); iChar++)
			_mesa.add(splittedStr[1].charAt(iChar));
	}
	
	public boolean resuelveTablero (Arbol arbolInstr)
	{
		Tablero clon = (Tablero) clone();
		
		clon.ejecutarArbol(arbolInstr);
		
		return clon.esSolucion();
	}
	
	private boolean ejecutarArbol(Arbol arbolInstr) {
		if (arbolInstr.getNombre().equals("MP")) {
			return ejecutarMP(arbolInstr.getHi().getNombre());
		}
		else if (arbolInstr.getNombre().equals("MM")) {
			return ejecutarMM(arbolInstr.getHi().getNombre());
		}
		else if (arbolInstr.getNombre().equals("NOT")) {
			return !ejecutarArbol(arbolInstr.getHi());
		}
		else if (arbolInstr.getNombre().equals("EQ")) {
			return ejecutarArbol(arbolInstr.getHi()) == ejecutarArbol(arbolInstr.getHd());
		}
		else if (arbolInstr.getNombre().equals("DU")) {
			int numRepeticiones = 0;
			int numMaxRepeticiones = (Integer) Opciones.getOpcion(Opciones.MAX_ITERACIONES);
			do {
				numRepeticiones++;
				ejecutarArbol(arbolInstr.getHi());
			} while (!ejecutarArbol(arbolInstr.getHd()) && numRepeticiones < numMaxRepeticiones);
						
			return numRepeticiones != numMaxRepeticiones;
		}
		
		return false;
	}
	
	/* Mueve el bloque <SN> a la cima de la pila */
	private boolean ejecutarMP(String x) {
		if (x.equals("SN") && _SN != -1) {
			_pila.add(_mesa.get(_SN));
			_mesa.remove(_SN);
			recalcularIndices();
			return true;
		}
		else 
			return false;
	}
	
	/* Mueve el bloque de la cima de la pila a la mesa */
	private boolean ejecutarMM(String x) {
		if ((_pila.size() != 0) && ((x.equals("BS") && _BS != -1) || x.equals("CP"))) {
			_mesa.add(_pila.get(_CP));
			_pila.remove(_CP);
			recalcularIndices();
			return true;
		}
		else 
			return false;
	}
	
	private void recalcularIndices() {
		// _BS
		char[] solucion = {'U', 'N', 'I', 'V', 'E', 'R', 'S', 'A', 'L'};
		boolean esCorrecto = true;
		for (int iChar = 0; iChar < _pila.size() && esCorrecto; iChar++) {
			esCorrecto = solucion[iChar] == _pila.get(iChar);
			if (!esCorrecto)
				_BS = iChar - 1;
		}
		if (esCorrecto)
			_BS = _pila.size() - 1;
		
		// _CP
		_CP = _pila.size() - 1;
		
		// _SN
		if (_mesa.size() == 0)
			_SN = -1;
		else
			_SN = _mesa.indexOf(solucion[_BS + 1]);
	}
	
	private boolean esSolucion() {
		char[] solucion = {'U', 'N', 'I', 'V', 'E', 'R', 'S', 'A', 'L'};
		boolean esSolucion = true;
		for (int iChar = 0; iChar < _pila.size() && esSolucion; iChar++)
			esSolucion = solucion[iChar] == _pila.get(iChar);
		
		return esSolucion && _pila.size() == solucion.length;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public Object clone() {
		Tablero clonedTab = new Tablero();
		clonedTab._pila = (ArrayList<Character>) this._pila.clone();
		clonedTab._mesa = (ArrayList<Character>) this._mesa.clone();
		clonedTab._CP = this._CP;
		clonedTab._BS = this._BS;
		clonedTab._SN = this._SN;
		
		return clonedTab;
	}
	
}
